package cn.tedu.v6;

import java.io.*;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.*;

/**
 *    Version v5       登录与退出  功能: 可以加在v3
 *    Version6   在线用户列表  统计上线名称
 *                消息转发
 *
 */
public class Server {
    private ServerSocket serverSocket;
    private static final Integer PORT=7777;

    private List<PrintWriter> allOut=new ArrayList<>();
    private List<String> onlineUsers=new ArrayList<>();
    //1. 存储在线客户: onlineUsers

    private Map<String,String> userDatabase;


    public Server() {
        try {
            serverSocket = new ServerSocket(PORT);

            userDatabase=new HashMap<>();

            userDatabase.put("111","123456");
            userDatabase.put("222","123456");

        } catch (BindException e) {
            System.out.println("端口号被占用异常");
        } catch (IOException e) {
            System.out.println("连接断开异常");
        }
    }
    public void start() {
        try {
            while (true) {
                System.out.println("等待客户端连接");
                Socket socket = serverSocket.accept();

                new Thread(new ClientHandler(socket)).start();
            }
        } catch (IOException e) {
            System.out.println("客户端断开连接");
        } finally {
            if(serverSocket!=null&&!serverSocket.isClosed()){
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    System.out.println("服务器关闭失败");
                }
                System.out.println("服务器关闭成功");
            }
        }
    }


    public static void main(String[] args) {
        new Server().start();
    }

    private synchronized void broadcastMessage(String message){
        for(PrintWriter pw: allOut){
            pw.println("消息广播"+message);

        }
    }
    //理解：broadcastMessage()  功能：获取客户端，转发消息
    private synchronized void updateOnlineUsers(){
            String userList="在线用户: " + String.join("、",onlineUsers);
            broadcastMessage(userList);
    }


    private class ClientHandler implements Runnable {
        private Socket socket;
        private String ip;
        private BufferedReader br;
        private PrintWriter pw;

        private String username;
        private String password;



        public ClientHandler(Socket s){
            this.socket=s;
            ip=socket.getInetAddress().getHostAddress();
            try {
                br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF8"));
                pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF8")), true);
                synchronized (allOut){
                    allOut.add(pw);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        private boolean Login(String user,String pass){
            return userDatabase.containsKey(user)&&userDatabase.get(user).equals(pass);
        }

        private void handleChat(){
            new Thread(()->{
                        try {
                            String message;
                            while ((message=br.readLine())!=null) {
                                System.out.println(username+message);
                                System.out.print("服务器端请输入: ");
                                broadcastMessage(username+message);

                            }

                        } catch (IOException e) {
                            System.out.println("客户端发来的消息断开了");
                        }
                    }
            ).start();
            Scanner input=new Scanner(System.in);
            while(true){
                System.out.println("服务器请输入: ");
                String sme=input.nextLine();
                pw.println("服务器端说: "+sme);

                if(sme.equals("exit")){
                    System.exit(0);
                }

            }
        }
        public void run() {
            try {
                pw.println("请输入用户名: ");
                username=br.readLine();
                pw.println("请输入密码: ");
                password=br.readLine();

                if(Login(username,password)){
                    pw.println("登陆成功,欢迎进入聊天室");

                    synchronized (onlineUsers) {
                        onlineUsers.add(username);
                        updateOnlineUsers();
                    }

                    //3. 判断客户端连接成功---加入集合中   【同步块: 监视对象---集合】
                    //3.2 客户端登陆成功---名字加入集合中  方法
                    //4. 同步块---从集合中一次移除用户
                    handleChat();
                }else{
                    pw.println("登陆失败,用户名或者密码错误");
                    socket.close();
                }

                } catch(IOException e){
                System.out.println("服务器端读写出现问题");
            }
                finally{
                synchronized (onlineUsers){
                    onlineUsers.remove(username);
                }

                synchronized (allOut){
                    allOut.remove(pw);
                }
                synchronized (onlineUsers) {
                    onlineUsers.remove(pw);
                }

                    if(pw!=null)
                        pw.close();
                    if(br!=null)
                        try {
                            br.close();
                        } catch (IOException e) {
                            System.out.println("服务器通讯内容失败");
                        }

                    if (socket != null && !socket.isClosed()) {
                        System.out.println();
                        try {
                            socket.close();
                        } catch (IOException e) {
                            System.out.println("客户端退出连接异常");
                        }
                    }
                    System.out.println("服务器退出了服务器连接");

                }
            }

            }

        }